package com.taoge.p4.common.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.taoge.p4.common.constants.RedisKeyConstant;
import com.taoge.p4.common.constants.SysUserContext;
import com.taoge.p4.common.constants.SysUserInfo;
import com.taoge.p4.common.constants.UserContext;
import com.taoge.p4.common.entity.Brand;
import com.taoge.p4.common.entity.ResponseData;
import com.taoge.p4.common.exception.ParamException;
import com.taoge.p4.common.mapper.BrandMapper;
import com.taoge.p4.common.params.BrandParam;
import com.taoge.p4.common.params.PageParam;
import com.taoge.p4.common.rabbit.RabbitConfig;
import com.taoge.p4.common.rabbit.exchange.RabbitmqExchange;
import com.taoge.p4.common.rabbit.msg.BrandProducterMsg;
import com.taoge.p4.common.rabbit.producer.RabbitmqProducer;
import com.taoge.p4.common.rabbit.routingKey.BrandRoutingKey;
import com.taoge.p4.common.service.BrandService;
import com.taoge.p4.common.utils.RedisUtil;
import com.taoge.p4.common.vo.BrandHistoryVO;
import com.taoge.p4.common.vo.BrandVO;
import io.lettuce.core.ScriptOutputType;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.ibatis.annotations.Lang;
import org.checkerframework.checker.units.qual.C;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author 77052
 * @description 针对表【brand(品牌)】的数据库操作Service实现
 * @createDate 2025-03-16 15:33:39
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class BrandServiceImpl extends ServiceImpl<BrandMapper, Brand>
        implements BrandService {

    private final BrandMapper brandMapper;

    private final StringRedisTemplate stringRedisTemplate;

    private final RabbitmqProducer rabbitmqProducer;

    private final Cache<String, IPage<BrandVO>> brandCache = Caffeine.newBuilder()
            .expireAfterWrite(5, TimeUnit.MINUTES)
            .maximumSize(100)
            .build();

    @Override
    public void edit(BrandParam param) {
        Brand exist = brandMapper.selectOne(new LambdaQueryWrapper<Brand>().eq(Brand::getName, param.getName()));

        if (exist != null) {
            //新增
            if (param.getId() == null) {
                throw new ParamException("品牌已存在");
            }
            //修改
            if (!exist.getId().equals(param.getId())) {
                throw new ParamException("品牌已存在");
            }
        }
        Brand brand = param.convertTo(Brand.class);
        if (brand.getId() == null) {
            brandMapper.insert(brand);
        } else {
            brandMapper.updateBrand(brand);
        }

    }

    @Override
    public void updateStatus(Long id) {
        brandMapper.update(null,
                new LambdaUpdateWrapper<Brand>()
                        .eq(Brand::getId, id)
                        .setSql("status = CASE WHEN status = 1 THEN 0 ELSE 1 END"));
    }

    @Override
    public IPage<BrandVO> selectPage(PageParam<Brand> page, BrandParam param) {
//        IPage<BrandVO> data = getByCaffine();
//        if (data != null) {
//            return data;
//        }
//        TypeReference<IPage<BrandVO>> typeReference = new TypeReference<>() {
//        };
//        data = RedisUtil.get(RedisKeyConstant.TAOGE_BRAND_LIST, typeReference);
//        if (data != null) {
//            setToCaffine(data);
//            return data;
//        }
        Brand brand = param.convertTo(Brand.class);
        IPage<Brand> list = brandMapper.list(page, brand);
        if (list.getRecords().isEmpty()) {
            return new Page<>();
        }
        IPage<BrandVO> brandVOIpage = new Page<>(list.getCurrent(), list.getSize(), list.getTotal());

        brandVOIpage.setRecords(list.getRecords().stream().map(item -> item.convertTo(BrandVO.class)).collect(Collectors.toList()));

//        RedisUtil.set(RedisKeyConstant.TAOGE_BRAND_LIST, brandVOIpage, 3600);
//        setToCaffine(brandVOIpage);

        return brandVOIpage;
    }

    private IPage<BrandVO> getByCaffine() {
        IPage<BrandVO> ifPresent = brandCache.getIfPresent(RedisKeyConstant.TAOGE_BRAND_LIST);
        if (ifPresent != null) {
            return ifPresent;
        }
        return null;
    }

    private void setToCaffine(IPage<BrandVO> data) {
        brandCache.put(RedisKeyConstant.TAOGE_BRAND_LIST, data);
    }

    public void removeCaffeine() {
        brandCache.invalidate(RedisKeyConstant.TAOGE_BRAND_LIST);
    }

    @Override
    public IPage<BrandHistoryVO> getHistory(Page<BrandHistoryVO> page) {
        long start = (page.getCurrent() - 1) * page.getSize();
        long end = page.getSize() * page.getCurrent() - 1;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeWithScores(RedisKeyConstant.HISTORY_BRAND + SysUserContext.getUserId(), start, end);
        if (typedTuples.isEmpty()) {
            return new Page<>();
        }

        List<Long> list = typedTuples.stream()
                .map(ZSetOperations.TypedTuple::getValue).filter(Objects::nonNull)
                .map(Long::parseLong)
                .toList();
//        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
//            Double score = typedTuple.getScore();//时间戳
//            String value = typedTuple.getValue();//品牌id
//        }
        List<Brand> brands = brandMapper.selectList(new LambdaQueryWrapper<Brand>().in(Brand::getId, list));
        if (brands.isEmpty()) {
            throw new RuntimeException("品牌不存在");
        }
        Map<String, Double> collect = typedTuples.stream().collect(Collectors.toMap(ZSetOperations.TypedTuple::getValue, ZSetOperations.TypedTuple::getScore));
        List<BrandHistoryVO> brandHistoryVOS = new ArrayList<>();
        for (Brand brand : brands) {
            BrandHistoryVO brandHistoryVO = new BrandHistoryVO();
            Double l = collect.get(brand.getId().toString());
            brandHistoryVO.setBrowsTime(DateFormatUtils.format(new Date(l.longValue()), "yyyy-MM-dd"));
            brandHistoryVO.setBrowsTimestamp(l.longValue());
            BeanUtils.copyProperties(brand, brandHistoryVO);
            brandHistoryVOS.add(brandHistoryVO);
        }
        //查询redis中对应key中的元素个数
        Long l = stringRedisTemplate.opsForZSet().zCard(RedisKeyConstant.HISTORY_BRAND + SysUserContext.getUserId());
        if (l == null) {
            l = 0L;
        }
        //给返回的集合数据排序，按照时间戳倒序
        IPage<BrandHistoryVO> pageList = new Page<>(page.getCurrent(), page.getSize());
        pageList.setRecords(brandHistoryVOS);
        pageList.setTotal(l);
        pageList.getRecords().sort(Comparator.comparing(BrandHistoryVO::getBrowsTimestamp).reversed());
        return pageList;
    }


    @Async
    @Override
    public void sendBrandHistory(BrandProducterMsg msg){
            stringRedisTemplate.opsForZSet().add(RedisKeyConstant.HISTORY_BRAND+ msg.getUserId(),msg.getBrandId().toString(),System.currentTimeMillis());
            log.info("添加历史记录");
            log.info("添加成功");
    }



//    public static void main(String[] args) {
//        //获取时间戳
//        Calendar calendar = Calendar.getInstance();
//        calendar.setTime(new Date());
//        calendar.add(Calendar.DATE, -1);
//        System.out.println(calendar.getTime().getTime());
//    }

}





